package com.manrai.springpractice.web;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.manrai.springpractice.domain.User;

@Controller
@RequestMapping("/register/form")
public class RegistrationController {
	private static final String MA_USER = "user";

	private final Logger log = Logger.getLogger(this.getClass().getName());

	@Autowired
	private Validator validator;

	public void setValidator(Validator validator) {
		this.validator = validator;
	}

	@RequestMapping(method = RequestMethod.GET)
	private String form(Model model) {
		model.addAttribute(MA_USER, new User());
		return "registration";
	}

	@RequestMapping(method = RequestMethod.POST)
	private String form(@ModelAttribute(MA_USER) User user,
			BindingResult bindingResult) {

		log.info("Processing User registration request: " + user);
		
		verifyBinding(bindingResult);
		validator.validate(user, bindingResult);
		
		if (bindingResult.hasErrors()) {
			bindingResult.reject("form.problems");
			return "registration";
		}
		
		return "redirect:confirm";
	}

	@InitBinder
	public void initBinder(WebDataBinder binder) {
		binder.setAllowedFields(new String[] { "firstName", "lastName",
				"email", "username", "password", "passwordConfirmation",
				"marketingOk", "acceptTerms" });
	}

	/**
	 * verify binding to avoid parameter hacking. Someone can try to modify
	 * enabled user attribute to true and skip user confirmation step in
	 * resgistration process. In order to avoid that we need to make sure that
	 * only those fields are bound by spring which were allowed in initBinder
	 * method!
	 * 
	 * @param result
	 */
	private void verifyBinding(BindingResult result) {
		String[] suppressedFields = result.getSuppressedFields();
		if (suppressedFields.length > 0) {
			throw new RuntimeException(
					"You've attempted to bind fields that haven't been allowed in initBinder(): "
							+ StringUtils.join(suppressedFields, ", "));
		}
	}
}
